/*
 * scc.h, SmartCam coprocessor interface
 *
 */

#ifndef __SCC_SCC_H
#define __SCC_SCC_H

#include <scu.h>
#include <globals.h>

#ifdef __cplusplus
#include <iostream>
extern "C" {
#endif

#define SCC_MANAGEMENT_PORT                      5474
#define SCC_DATA_PORT                            5475
#define SCC_MAX_ARGUMENTS                        8
#define SCC_MAX_MESSAGE_SIZE                     (SCOS_MTU+sizeof(struct scc_hdr_s))
#define SCC_MASTER_PROCESSOR                     255

#define SCC_SOCKET_BUFSIZE 131072
#define SCC_MAX_WINDOW     32768

#define SCC_MSGTYPE_BUFFERCREATE                 1
#define SCC_MSGTYPE_BUFFERFINALIZE               2
#define SCC_MSGTYPE_BUFFERCOMPLETED              3
#define SCC_MSGTYPE_TRANSPORTCREATE              4
#define SCC_MSGTYPE_OPERATIONENQUEUE             5
#define SCC_MSGTYPE_OPERATIONARGUMENT            6
#define SCC_MSGTYPE_OPERATIONRESULT              7
#define SCC_MSGTYPE_OPERATIONCOMPLETED           8
#define SCC_MSGTYPE_BUFFERDATA                   9
#define SCC_MSGTYPE_BUFFERDRY                    10
#define SCC_MSGTYPE_BUFFERACK                    11
#define SCC_MSGTYPE_BUFFERWINDOW                 12
#define SCC_MSGTYPE_BUFFERDEADLOCKED             13

typedef struct scc_hdr_s
{
  int source, destination;
  unsigned short int type;
  unsigned long int size;
} scc_hdr_t;

typedef struct scc_msg_s
{
  struct scc_hdr_s header;
  unsigned short int opid, optype, argid, argtype, argintent;
  int processor;
  unsigned int size;
  unsigned char data[8]; /* Must be 4-byte aligned for TriMedia! */

#ifdef __cplusplus
  friend std::ostream &operator<<(std::ostream &os, const scc_msg_s &msg);
  bool operator==(const scc_msg_s &msg) const
  {
    return !memcmp(this, &msg, sizeof(scc_msg_s));
  }
#endif
} scc_msg_t;

typedef struct scc_datamsg_s
{
  struct scc_hdr_s header;
  unsigned short int buffer;
  unsigned char data[8]; /* Make it at least as long as scc_ack_t */
} scc_datamsg_t;

typedef struct scc_ack_s
{
  struct scc_hdr_s header;
  unsigned short int buffer;
  unsigned long int acknowledged, window;
} scc_ack_t;

typedef void (*scc_controlcallback_t)(struct scc_hdr_s*);
typedef void (*scc_datacallback_t)(struct scc_hdr_s*);
typedef unsigned long int(*scc_querycallback_t)(int); 

typedef struct scc_proc_s
{
  int id;
  char *name;
  struct sockaddr address;
  int addrlen;
  SOCKET control_fd, incoming_data_fd, outgoing_data_fd;

  scc_controlcallback_t controlcallback;
  scc_datacallback_t datacallback;
} scc_proc_t;

void sccInit(struct sockaddr *myaddr, int addrlen);
void sccSendMessage(scc_hdr_t *msg);
void sccMasterSetup(scc_controlcallback_t controlcallback, scc_datacallback_t datacallback);
void sccCoprocessorSetup(int proc, scc_controlcallback_t controlcallback, scc_datacallback_t datacallback);
void sccOpenControlConnection(scc_proc_t *p);
void sccOpenDataConnection(scc_proc_t *p);
void sccAwaitControlConnection(void);
void *sccIncomingConnectionThread(void *dummy);
void *sccIncomingControlThread(void *proc);
void *sccIncomingDataThread(void *proc);

// ***

#include "scu.h"

typedef struct scc_trans_param_s
{
  int src, dest, destbuf;
  scu_buf_t *buf;
  scu_bufptrid_t ptr;
} scc_trans_param_t;

typedef struct scc_window_s
{
  unsigned long int window, unacked;
  scos_mutex_t lock;
  scos_cond_t condition;
} scc_window_t;

typedef struct scc_watch_s
{
  int source;
  int destination, buffer;
} scc_watch_t;

typedef struct scc_transproc_s
{
  int id;
  scc_datacallback_t datacallback;
  scc_querycallback_t querycallback;
} scc_transproc_t;

void sccTransportInit(void);
void sccTransportCreate(scu_buf_t *buf, int src, int dest, int destbuf);
void *sccTransportThread(void *arg);
void sccTransportRegister(int proc, scc_datacallback_t datacallback,
                          scc_querycallback_t querycallback);
void *sccWatchBufferThread(void* dummy);
void sccTransportSend(int src, int dest, int destbuf, unsigned long int length, char *data);
void sccTransportReceive(struct scc_hdr_s *hdr);

#ifdef __cplusplus
}
#endif

#endif /* __SCC_SCC_H */
